/*
 * Client.cpp
 *
 *  Created on: 2009-01-10
 *      Author: tomaszd
 */

#include "UdpClient.h"
#include <fstream>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include "../CommunicationStructs.h"
#include <assert.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>

#define  CLIENT_RECEIVE_TIMEOUT_S 4
using namespace std;

UdpClient::UdpClient()
{
	addr_len = sizeof(struct sockaddr);
	slen = sizeof(struct sockaddr);
}

UdpClient::~UdpClient()
{
	// TODO Auto-generated destructor stub
}

/*=========================================================================================*/

void UdpClient::client_config(char * path_to_conf)
{
	string line;
	int i = 1;
	ifstream config_file;
	if (NULL == path_to_conf)
	{
		config_file.open("udp-client/options.cfg", ios::in);
	}
	else
	{
		config_file.open(path_to_conf, ios::in);
	}
	if (config_file.is_open())
	{
		//	cout << "Odczytuje plik konfiguracyjny..." << endl;
		//	cout << "Zczytuje linijke" <<endl;
		while (!config_file.eof())
		{

			//line.clear();
			line = "";
			getline(config_file, line);
			if (!line.compare(";"))
				break;
			int col = line.find('=', 0);
			line = line.substr(col+1, line.length());
			switch (i)
			{
			case 1:
				client_options.server_port = atoi(line.c_str());
				//	cout << client_options.server_port <<endl;
				break;
			case 2:
				inet_aton(line.c_str(),
						&(client_options.server_addr));
				//cout << client_options.server_addr <<endl;
				break;
			case 3:
				strcpy((char*)&client_options.nick,
						line.c_str());
				//cout << client_options.nick <<endl;
				break;
			case 4:
				client_options.passwd = atoi(line.c_str());
				//cout << client_options.passwd <<endl;
				break;
			default:
				cout << "Blad w pliku konfiguracyjnym!" << endl;
				exit(EXIT_FAILURE);
			}

			i++;
		}

		config_file.close();

		//		cout << "Port serwera	: " << client_options.server_port << endl;
		//		cout << "Adres serwera	: " << inet_ntoa(client_options.server_addr) << endl;
		//		cout << "Nick	: " << client_options.nick << endl;
	}
	else
	{
		cout << "Upsss...\tNie znalazłem pliku konfiguracyjnego!"
				<< endl;
		exit(EXIT_FAILURE);
	}
}

/*=========================================================================================*/

void UdpClient::submit_player()
{
	client_addr.sin_family = AF_INET;
	client_addr.sin_port = htons(0);
	client_addr.sin_addr.s_addr = INADDR_ANY; //inet_addr("10.7.10.32");
	memset(&(client_addr.sin_zero), '\0', 8);

	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(client_options.server_port);
	server_addr.sin_addr= client_options.server_addr;
	memset(&(server_addr.sin_zero), '\0', 8);

	if ((sh = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))== -1)
	{
		perror("socket");
		exit(EXIT_FAILURE);
	}

	if (bind(sh, (struct sockaddr*)&client_addr, addr_len) == -1)
	{
		perror("bind");
		exit(EXIT_FAILURE);
	}

	player_decl.passwd = client_options.passwd;
	strcpy((char*)&player_decl.nick, (char*)&client_options.nick);
	if (sendto(sh, (char*)&player_decl, sizeof(declaration), 0,
			(struct sockaddr*)&server_addr, addr_len) == -1)
	{
		perror("sendto");
		exit(1);
	}

}

/*=========================================================================================*/

bool UdpClient::connect_to_game()
{
	// ustawiamy limit czasu oczekiwania funkcji 'recvfrom'
	tv.tv_sec = CLIENT_RECEIVE_TIMEOUT_S;
	tv.tv_usec = 0;
#ifdef TIMEOUT_SUPPPORTED	
	if (setsockopt(sh, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv))
			== -1)
	{
		perror("setsockopt");
		return false;
	}
#endif
	if (recvfrom(sh, (char*)&init_struct, sizeof(init), 0,
			(struct sockaddr*)&server_addr, &slen) == -1)
	{
		perror("recvfrom");
		return false;
	}
	else
	{
		if (init_struct.accept == -1)
		{
			cout
					<< "Gracz o podanym nicku istnieje!\nZmien nick i sprobuj ponownie"
					<< endl;
			assert("Gracz o takim nicku istnieje" == NULL);
			return false;
		}
		else if (init_struct.accept == 0)
		{
			cout << "Podales bledne haslo!" << endl;
			assert("Bledne haslo" == NULL);
			return false;
		}
		else
		{
			close(sh);

			game_addr = init_struct.addr;
			game_addr.sin_addr.s_addr = htonl(INADDR_ANY);

			if ((sh = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))
					== -1)
			{
				perror("socket");
				return false;
			}

			int reuse = 1;
			if (setsockopt(sh, SOL_SOCKET, SO_REUSEADDR,
					(char*)&reuse, sizeof(int)) == -1)
			{
				perror("setsockopt");
				return false;
			}

			if (bind(sh, (struct sockaddr*)&game_addr, addr_len)
					== -1)
			{
				perror("bind");
				return false;
			}

			//ustawienie opcji gniazda i przylaczenie sie do grupy multicastowej
			mreq.imr_multiaddr.s_addr
					= init_struct.addr.sin_addr.s_addr;
			mreq.imr_interface.s_addr = htonl(INADDR_ANY);
			if (setsockopt(sh, IPPROTO_IP, IP_ADD_MEMBERSHIP,
					(char*)&mreq, sizeof(mreq)) == -1)
			{
				perror("setsockopt");
				return false;
			}
			cout << "Przylaczyles  sie do gry" << endl;
			return true;
		}

	}
}

/*=========================================================================================*/

void UdpClient::receive(char *str, unsigned long int size)
{
	//	cout << "receive()" << endl;
	tv.tv_sec = CLIENT_RECEIVE_TIMEOUT_S;
	tv.tv_usec = 0;
#ifdef TIMEOUT_SUPPPORTED		
	if (setsockopt(sh, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv))
			== -1)
	{
		perror("setsockopt");
		return;
	}
#endif 
	
	if (recvfrom(sh, str, size, 0, (struct sockaddr*)&server_addr, &slen)
			== -1)
	{
		perror("recvfrom");
		exit(EXIT_FAILURE);
	}

}

/*=========================================================================================*/

void UdpClient::send(char *str, unsigned long int size)
{
	//	cout << "send()" << endl;
	if (sendto(sh, str, size, 0, (struct sockaddr*)&server_addr, addr_len)
			== -1)
	{
		perror("sendto");
		exit(EXIT_FAILURE);
	}
}

/*=========================================================================================*/
